/*
 * $Id: TestADIFParser.m 89 2009-07-15 03:36:56Z jon@bway.net $
 * Chalk
 *
 * Created 5/31/09
 * Copyright Jon Gordon
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#import "TestADIFParser.h"

#import "QEADIFInternal.h"
#import "QEADIFParser.h"

//static const NSString *EMPTY_STRING = @"";

#define ADIF_SRC1_LF @"\n<CALL:6>cx4aaj\n<BAND:3>15M\n<MODE:4>RTTY\n<QSO_DATE:8>20080928\n<TIME_ON:6>183200\n<FREQ:6>21.106\n<EOR>\n<CALL:4>n2bj\n<BAND:3>40M\n<MODE:5>PSK31\n<QSO_DATE:8>20081004\n<TIME_ON:6>000000\n<FREQ:5>7.072\n<EOR>\n<CALL:5>ai4of\n<BAND:3>40M\n<MODE:5>PSK31\n<QSO_DATE:8>20081004\n<TIME_ON:6>010700\n<FREQ:5>7.072\n<EOR>\n"

#define ADIF_SRC1_ERR @"\n<CALL:6>cx4aaj\n<:3>15M\n<MODE:4>RTTY\n<QS?O_DATE:8>20080928\n<TIME_ON:q>183200\n<FREQ:>21.106\n<EOR>\n<CALL:4:>n2bj\n<BAND:3>40M\n<MODE:5>PSK31\n<QSO_DATE:8:z>20081004\n<TIME_ON:6>000000\n<FREQ:5>7.072\n<EOR>\n<CALL:5>ai4of\n<BAND:3>40M\n<MODE:5>PSK31\n<QSO_DATE:8:D20081004\n<TIME_ON:6>010700\n<FREQ:5>7.072\n<EO"

static NSArray *ADIF_SRC1_LF_ELEMENTS;
static NSArray *ADIF_SRC1_LF_CLEANED;
static NSArray *ADIF_SRC1_ERR_ELEMENTS;


@implementation TestADIFParser
- (void)setUp
{
    //-NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [super setUp];
    
    ADIF_SRC1_LF_ELEMENTS = [[NSArray arrayWithObjects:
                              @"comment(1,1):\"\n\"",
                              @"field(2,1)<CALL>cx4aaj",
                              @"comment(2,15):\"\n\"",
                              @"field(3,1)<BAND>15M",
                              @"comment(3,12):\"\n\"",
                              @"field(4,1)<MODE>RTTY",
                              @"comment(4,13):\"\n\"",
                              @"field(5,1)<QSO_DATE>20080928",
                              @"comment(5,21):\"\n\"",
                              @"field(6,1)<TIME_ON>183200",
                              @"comment(6,18):\"\n\"",
                              @"field(7,1)<FREQ>21.106",
                              @"comment(7,15):\"\n\"",
                              @"tag(8,1)<EOR>",
                              @"comment(8,6):\"\n\"",
                              @"field(9,1)<CALL>n2bj",
                              @"comment(9,13):\"\n\"",
                              @"field(10,1)<BAND>40M",
                              @"comment(10,12):\"\n\"",
                              @"field(11,1)<MODE>PSK31",
                              @"comment(11,14):\"\n\"",
                              @"field(12,1)<QSO_DATE>20081004",
                              @"comment(12,21):\"\n\"",
                              @"field(13,1)<TIME_ON>000000",
                              @"comment(13,18):\"\n\"",
                              @"field(14,1)<FREQ>7.072",
                              @"comment(14,14):\"\n\"",
                              @"tag(15,1)<EOR>",
                              @"comment(15,6):\"\n\"",
                              @"field(16,1)<CALL>ai4of",
                              @"comment(16,14):\"\n\"",
                              @"field(17,1)<BAND>40M",
                              @"comment(17,12):\"\n\"",
                              @"field(18,1)<MODE>PSK31",
                              @"comment(18,14):\"\n\"",
                              @"field(19,1)<QSO_DATE>20081004",
                              @"comment(19,21):\"\n\"",
                              @"field(20,1)<TIME_ON>010700",
                              @"comment(20,18):\"\n\"",
                              @"field(21,1)<FREQ>7.072",
                              @"comment(21,14):\"\n\"",
                              @"tag(22,1)<EOR>",
                              @"comment(22,6):\"\n\"",
                              @"[eoi](23,1)",
                              nil] retain];
    
    ADIF_SRC1_LF_CLEANED = [[NSArray arrayWithObjects:
                             @"comment(1,1):\"\"",
                             @"field(2,1)<CALL>cx4aaj",
                             @"field(3,1)<BAND>15M",
                             @"field(4,1)<MODE>RTTY",
                             @"field(5,1)<QSO_DATE>20080928",
                             @"field(6,1)<TIME_ON>183200",
                             @"field(7,1)<FREQ>21.106",
                             @"tag(8,1)<EOR>",
                             @"field(9,1)<CALL>n2bj",
                             @"field(10,1)<BAND>40M",
                             @"field(11,1)<MODE>PSK31",
                             @"field(12,1)<QSO_DATE>20081004",
                             @"field(13,1)<TIME_ON>000000",
                             @"field(14,1)<FREQ>7.072",
                             @"tag(15,1)<EOR>",
                             @"field(16,1)<CALL>ai4of",
                             @"field(17,1)<BAND>40M",
                             @"field(18,1)<MODE>PSK31",
                             @"field(19,1)<QSO_DATE>20081004",
                             @"field(20,1)<TIME_ON>010700",
                             @"field(21,1)<FREQ>7.072",
                             @"tag(22,1)<EOR>",
                             @"[eoi](23,1)",
                             nil] retain];
    
    ADIF_SRC1_ERR_ELEMENTS = [[NSArray arrayWithObjects:
                               @"comment(1,1):\"\n\"",
                               @"field(2,1)<CALL>cx4aaj",
                               @"comment(2,15):\"\n\"",
                               @"Syntax error at line 3, position 2: missing name of field or tag.",
                               @"comment(3,3):\"3>15M\n\"",
                               @"field(4,1)<MODE>RTTY",
                               @"comment(4,13):\"\n\"",
                               @"Syntax error at line 5, position 4: illegal character in name of field or tag \"QS?\".",
                               @"comment(5,5):\"O_DATE:8>20080928\n\"",
                               @"Syntax error at line 6, position 10: data length expected but missing from \"<TIME_ON:q\".",
                               @"comment(6,11):\">183200\n\"",
                               @"Syntax error at line 7, position 7: data length expected but missing from \"<FREQ:>\".",
                               @"comment(7,8):\"21.106\n\"",
                               @"tag(8,1)<EOR>",
                               @"comment(8,6):\"\n\"",
                               @"Syntax error at line 9, position 9: missing type code from field \"<CALL:4:>\".",
                               @"comment(9,9):\">n2bj\n\"",
                               @"field(10,1)<BAND>40M",
                               @"comment(10,12):\"\n\"",
                               @"field(11,1)<MODE>PSK31",
                               @"comment(11,14):\"\n\"",
                               @"Syntax error at line 12, position 13: invalid type code encountered in field \"<QSO_DATE:8:z\".",
                               @"comment(12,14):\">20081004\n\"",
                               @"field(13,1)<TIME_ON>000000",
                               @"comment(13,18):\"\n\"",
                               @"field(14,1)<FREQ>7.072",
                               @"comment(14,14):\"\n\"",
                               @"tag(15,1)<EOR>",
                               @"comment(15,6):\"\n\"",
                               @"field(16,1)<CALL>ai4of",
                               @"comment(16,14):\"\n\"",
                               @"field(17,1)<BAND>40M",
                               @"comment(17,12):\"\n\"",
                               @"field(18,1)<MODE>PSK31",
                               @"comment(18,14):\"\n\"",
                               @"Syntax error at line 19, position 14: closing angle bracket (\'>\') missing from field \"<QSO_DATE:8:D\".",
                               @"comment(19,14):\"20081004\n\"",
                               @"field(20,1)<TIME_ON>010700",
                               @"comment(20,18):\"\n\"",
                               @"field(21,1)<FREQ>7.072",
                               @"comment(21,14):\"\n\"",
                               @"Syntax error at line 22, position 4: unexpected end of input.",
                               @"[eoi](22,4)",
                               nil] retain];
} // setUp

- (void)tearDown
{
    //-NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [ADIF_SRC1_LF_ELEMENTS release];
    [ADIF_SRC1_ERR_ELEMENTS release];
    
    [super tearDown];
} // tearDown


- (void)testCompilation
{
    STAssertTrue(YES, @"CAN'T HAPPEN");
} // testCompilation


- (void)testAnalysis
{
    QEADIFParser *parser = [[QEADIFParser alloc] initWithSrc:ADIF_SRC1_LF];
    int i = 0;
    
    while ([parser hasMoreElements]) {
        id element = [parser nextElement];
        STAssertNotNil(element, @"Parser should return non-nil element.");
        if (nil != element) {
            STAssertTrue([[element description] isEqual:[ADIF_SRC1_LF_ELEMENTS objectAtIndex:i]],
                         @"element should be %@; element is %@",
                         [ADIF_SRC1_LF_ELEMENTS objectAtIndex:i],
                         [element description]);
        } // if
        
        if (++i >= [ADIF_SRC1_LF_ELEMENTS count]) {
            break;
        } // if
    } // while
    
    STAssertFalse([parser hasMoreElements],
                  @"Parser has too many elements.");
    STAssertTrue(i == [ADIF_SRC1_LF_ELEMENTS count],
                 @"Parser didn't supply enough elements: should have %d; had %d.",
                 [ADIF_SRC1_LF_ELEMENTS count],
                 i);
    
    [parser release];
} // testAnalysis


- (void)testAnalysisWithErrors
{
    QEADIFParser *parser = [[QEADIFParser alloc] initWithSrc:ADIF_SRC1_ERR];
    int i = 0;
    
    while ([parser hasMoreElements]) {
        id element = [parser nextElement];
        STAssertNotNil(element, @"Parser should return non-nil element.");
        if (nil != element) {
            STAssertTrue([[element description] isEqual:[ADIF_SRC1_ERR_ELEMENTS objectAtIndex:i]],
                         @"element should be %@; element is %@",
                         [ADIF_SRC1_ERR_ELEMENTS objectAtIndex:i],
                         [element description]);
        } // if
        
        if (++i >= [ADIF_SRC1_ERR_ELEMENTS count]) {
            break;
        } // if
    } // while
    
    STAssertFalse([parser hasMoreElements],
                  @"Parser has too many elements.");
    STAssertTrue(i == [ADIF_SRC1_ERR_ELEMENTS count],
                 @"Parser didn't supply enough elements: should have %d; had %d.",
                 [ADIF_SRC1_ERR_ELEMENTS count],
                 i);
    
    [parser release];
} // testAnalysisWithErrors

- (void)testAllElements
{
    NSMutableArray *elements = [QEADIFParser allElementsFromSource:ADIF_SRC1_LF];
    STAssertNotNil(elements,
                   @"Couldn't create array of all elements.");
    if (nil != elements) {
        STAssertEquals([ADIF_SRC1_LF_ELEMENTS count],
                       [elements count],
                       @"Elements array should have %lu members; actually has %lu members.",
                       ((unsigned long) [ADIF_SRC1_LF_ELEMENTS count]),
                       ((unsigned long) [elements count]));
        NSUInteger n = [ADIF_SRC1_LF_ELEMENTS count];
        if ([elements count] < n) {
            n = [elements count];
        } // if
        NSUInteger i;
        for (i = 0; i < n; ++i) {
            STAssertEqualObjects([ADIF_SRC1_LF_ELEMENTS objectAtIndex:i],
                                 [[elements objectAtIndex:i] description],
                                 @"Element at index %lu should be \"%@\"; actually is \"%@\".",
                                 i,
                                 [ADIF_SRC1_LF_ELEMENTS objectAtIndex:i],
                                 [[elements objectAtIndex:i] description]);
        } // for
    } // if
} // testAllElements

- (void)testCleanedElements
{
    NSMutableArray *elements = [QEADIFParser cleanedElementsFromSource:ADIF_SRC1_LF];
    STAssertNotNil(elements,
                   @"Couldn't create array of all elements.");
    if (nil != elements) {
        // BEGIN DEBUG
        int num = 0;
        //-NSLog(@"  ELEMENTS AFTER CLEANING:");
        for (QEADIFElement *e in elements) {
            //-NSLog(@"    %4d: %@", ++num, [e description]);
        } // for
        // END DEBUG
        
        STAssertEquals([ADIF_SRC1_LF_CLEANED count],
                       [elements count],
                       @"Elements array should have %lu members; actually has %lu members.",
                       ((unsigned long) [ADIF_SRC1_LF_CLEANED count]),
                       ((unsigned long) [elements count]));
        NSUInteger n = [ADIF_SRC1_LF_CLEANED count];
        if ([elements count] < n) {
            n = [elements count];
        } // if
        NSUInteger i;
        for (i = 0; i < n; ++i) {
            STAssertEqualObjects([ADIF_SRC1_LF_CLEANED objectAtIndex:i],
                                 [[elements objectAtIndex:i] description],
                                 @"Element at index %lu should be \"%@\"; actually is \"%@\".",
                                 i,
                                 [ADIF_SRC1_LF_CLEANED objectAtIndex:i],
                                 [[elements objectAtIndex:i] description]);
        } // for
    } // if
} // testCleanedElements
@end
